<?php

namespace console\controllers;

use common\models\cb\CBCalculator;
use common\models\cb\CBEventDispatcher;
use common\models\cb\CBInvoke;
use common\models\cb\CBLogger;
use common\models\cb\CBMailer;
use common\models\cb\CBMultiplier;
use common\models\cb\CBMyCallable;
use common\models\cb\CBMyClass;
use common\models\cb\CBUser;
use common\models\cb\CBUserNotifier;
use common\models\cb\CBValidator;
use Yii;
use yii\console\Controller;
use yii\helpers\Url;

/**
 * @Desc:PHP 函数参数为对象方法的写法案例
 * @Date: 2025/7/21
 * @Developer zp
 */
class CallableController extends Controller
{
    /**
     * @desc 1. 基本对象方法作为回调 php ./yii callable/zp1
     * @return void
     * @Date: 2025/7/18
     */
    public function actionZp1()
    {
        $calc = new CBCalculator();

        $callable1 = [$calc, 'add'];
        $callable2 = [$calc, 'multiply'];
        if (!is_callable($callable1)) {
            throw new \Exception('no such function add');
        }

        // 传递对象方法作为参数
        $result = CBInvoke::compute($callable1, 5, 3); // 输出 8
        echo $result . PHP_EOL;

        if (!is_callable($callable2)) {
            throw new \Exception('no such function multiply');
        }
        $result = CBInvoke::compute($callable2, 5, 3); // 输出 15
        echo $result . PHP_EOL;
    }

    /**
     * @desc 2. 使用 callable 类型提示
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp2()
    {
        $logger = new CBLogger();
        $callable = [$logger, 'logMessage'];
        if (!is_callable($callable)) {
            throw new \Exception('no such function logMessage');
        }
        CBInvoke::processWithLogging($callable, ['id' => 123, 'name' => '测试']);
    }

    /**
     * @desc 3. 静态方法作为回调
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp3()
    {
        $callable1 = ['common\models\cb\CBStringUtils', 'toUpper'];//传递静态方法
        $callable2 = 'common\models\cb\CBStringUtils::toLower';// 也可以这样写（PHP 5.2.3+）

        if (!is_callable($callable1)) {
            throw new \Exception('no such function toUpper');
        }
        if (!is_callable($callable2)) {
            throw new \Exception('no such function toLower');
        }
        $result = CBInvoke::transformString('Hello', $callable1); // 输出 "HELLO"
        echo $result . PHP_EOL;

        $result = CBInvoke::transformString('Hello', $callable2); // 输出 "hello"
        echo $result . PHP_EOL;
    }

    /**
     * @desc 4. 在数组函数中使用对象方法
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp4()
    {
        $validator = new CBValidator();
        $numbers = [1, 2, 3, 4, 5, 6];

        $callable = [$validator, 'isEven'];
        if (!is_callable($callable)) {
            throw new \Exception('no such function isEven');
        }
        // 使用 array_filter 和对象方法
        $evenNumbers = array_filter($numbers, $callable);
        print_r($evenNumbers); // 输出 [2, 4, 6]
    }

    /**
     * @desc 5. 可调用对象（__invoke 魔术方法）
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp5()
    {
        $double = new CBMultiplier(2);
        $triple = new CBMultiplier(3);


        $callable1 = $double;
        $callable2 = $triple;
        if (!is_callable($callable1)) {
            throw new \Exception('no such function __invoke');
        }
        if (!is_callable($callable2)) {
            throw new \Exception('no such function __invoke');
        }

        echo CBInvoke::applyOperation(5, $callable1) . PHP_EOL; // 输出 10
        echo CBInvoke::applyOperation(5, $callable2) . PHP_EOL; // 输出 15
    }

    /**
     * @desc 6. 依赖注入中的回调用法
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp6()
    {
        $mailer = new CBMailer();
        $notifier = new CBUserNotifier($mailer);


        // 传递对象方法作为消息生成器
        $messageService = new CBInvoke();

        $callable = [$messageService, 'getWelcomeMessage'];
        if (!is_callable($callable)) {
            throw new \Exception('no such function getWelcomeMessage');
        }
        $notifier->notifyUser('user@example.com', $callable);
    }

    /**
     * @desc 7. 事件调度器实现
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp7()
    {
        $dispatcher = new CBEventDispatcher();
        $userHandler = new CBUser();

        $callable = [$userHandler, 'onUserRegistered'];
        if (!is_callable($callable)) {
            throw new \Exception('no such function onUserRegistered');
        }

        // 添加对象方法作为事件监听器
        $dispatcher->addListener('user.registered', $callable);

        // 触发事件
        $dispatcher->dispatch('user.registered', [
            'username' => '张三',
            'email' => 'zhangsan@example.com'
        ]);
    }

    /**
     * @desc 1. callable 类型
     *          callable 是 PHP 中的一种伪类型，用于指定可以调用的内容。它可以接受以下几种形式：
     *       2. is_callable() 函数
     *          is_callable() 用于检查变量是否可以作为函数调用。
     * @return void
     * @Date: 2025/7/21
     */
    public function actionZp8()
    {
        //1.1 普通函数
        /*function myFunction($a, $b)
        {
            return $a + $b;
        }

        $callable1 = 'myFunction';
        if (!is_callable($callable1)) {
            throw new \Exception('no such function myFunction');
        }*/

        //////////////////////////////////////////////////////////////////////

        //1.2 对象方法
        $obj = new CBMyClass();
        $callable2 = [$obj, 'myMethod'];
        if (!is_callable($callable2)) {
            throw new \Exception('no such function CBMyClass.myMethod');
        }

        //////////////////////////////////////////////////////////////////////

        //1.3 静态方法
        $callable31 = ['common\models\cb\CBMyClass', 'myStaticMethod'];
        // 或
        $callable32 = 'common\models\cb\CBMyClass::myStaticMethod';
        if (!is_callable($callable31)) {
            throw new \Exception('no such function common\models\cb\CBMyClass.myStaticMethod');
        }
        if (!is_callable($callable32)) {
            throw new \Exception('no such function common\models\cb\CBMyClass.myStaticMethod');
        }

        //////////////////////////////////////////////////////////////////////

        //1.4 匿名函数
        $callable4 = function ($a, $b) {
            return $a / $b;
        };
        if (!is_callable($callable4)) {
            throw new \Exception('no such function 无此匿名函数');
        }

        //////////////////////////////////////////////////////////////////////

        //1.5 可调用对象（实现 __invoke() 方法的对象）
        $callable5 = new CBMyCallable();
        if (!is_callable($callable5)) {
            throw new \Exception('no such function __invoke');
        }

    }
}

